Conversation
|
@all-hands-bot live Agent Canvas evidence is now included. Please review this current head and submit an explicit APPROVE review if there are no blocking findings. |
|
👋 This PR needs a couple of things fixed before OpenHands can review it:
Push an update once this is addressed and this check re-runs automatically. This is an automated check - no AI was used to generate this comment. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Review: feat: delegate issue triage to subject agents
I reviewed the current head (factory/triage-subject-turns) against main, ran the full test suite, and checked catalog/bundle consistency.
What the PR does
The github-issue-triage extension is refactored from an SDK-coupled automation that ran its own conversation runtime into a lightweight scanner that delegates triage work to Automation's subject-turn API. The worker no longer imports openhands.sdk (RemoteConversation, RemoteWorkspace, register_default_tools) or manages AGENT_SERVER_URL / SESSION_API_KEY / AUTOMATION_CONVERSATION_ID. Instead, submit_subject_turn() posts each changed issue to AUTOMATION_SUBJECT_TURN_URL with a Bearer $AUTOMATION_RUN_TOKEN credential, keyed by GitHub's immutable repository ID + issue number, and idempotent via a content digest.
Verification performed
- Full test suite: 823 passed, 24 skipped (includes the 3 new triage delivery tests, all catalog/sync/schema tests).
- Ruff: clean on
worker.pyandtest_github_triage_delivery.py. - Generated catalog:
npm run build:automationsandnpm run build:skillsproduce no diff —bundle-index.jsandskills/index.jsare in sync with source files. - Bundle-index ↔ source: confirmed
worker.pyandgithub_client.pyinbundle-index.jsmatch the source files byte-for-byte.
Code quality observations (positive)
- Clean separation of concerns: the scanner is a plain host command; only the delegated agent receives a conversation runtime. SDK imports, workspace lifecycle, and session management are fully removed.
- Idempotency:
subject_keyuses{repository_id}:issue:{number}(immutable repo ID, survives renames) andidempotency_keyuses the content digest, so re-runs are safe. - Defensive improvements:
issue.get("labels", [])instead ofissue["labels"],sort_keys=Truein the digest serialization for deterministic ordering. - Prompt security: the delegated prompt passes only the env-var name (
token_name), never the value, instructs the agent never to print it, and scopes mutations to a single issue in a single repository. - Tests are real, not mocks of mocks: the tests exercise the actual
worker.pyentrypoint via thegithub_automation_helpersfixture (which reads the manifest and loads the real bundle), mocking only thesubmit_subject_turnandurlopenboundaries.
Non-blocking finding
SKILL.md throughput description is stale. The last paragraph still reads:
Each scheduled run triages at most one changed issue per repository.
The old code used break after the first changed issue (one per run). The new code uses continue to skip already-triaged issues and submits all changed eligible issues per repository per run. The PR description itself says "For every changed eligible issue, it submits an idempotent subject turn," which matches the code. The SKILL.md text should be updated to reflect this (e.g., "Each scheduled run triages all changed eligible issues per repository"). This is documentation-only and does not block merge.
Verdict
No blocking findings. The architectural change is sound, the code is clean and well-tested, and the generated assets are consistent. Approving.
Generated by OpenHands AI on behalf of the user.
|
@neubig I reviewed the current head and submitted an explicit APPROVE review (#584 (review)). Verification performed:
Non-blocking finding: SKILL.md's last paragraph still says "Each scheduled run triages at most one changed issue per repository," but the new code uses Generated by OpenHands AI on behalf of the user. |
c0634a5 to
4c0c313
Compare
|
@all-hands-bot Please re-review the current rebased head and explicitly approve it if there are no blocking findings. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Re-review of rebased head (4c0c313)
I re-reviewed the current rebased head (factory/triage-subject-turns @ 4c0c313) against main, re-ran the full suite, and re-checked catalog/bundle consistency.
Verification performed
- Full test suite: 905 passed, 24 skipped (includes the 3 triage delivery tests).
- Ruff: clean on
worker.pyandtest_github_triage_delivery.py. - Generated catalog:
npm run build:automationsandnpm run build:skillsproduce no diff —bundle-index.jsandskills/index.jsare in sync with source. - Bundle-index ↔ source:
worker.pyandgithub_client.pyinbundle-index.jsmatch the source files byte-for-byte.
Re-review observations
The rebased head is content-identical to the head I approved previously — the rebase replayed cleanly onto the latest main with no conflicts or changes. The architectural refactor (scanner delegates to Automation's subject-turn API; no SDK imports, no workspace/conversation lifecycle in the worker) remains sound:
submit_subject_turn()posts{source, subject_key, turn, idempotency_key}toAUTOMATION_SUBJECT_TURN_URLwith aBearer $AUTOMATION_RUN_TOKEN— no conversation/session/workspace machinery leaked into the scanner.- Idempotency keys are
{repository_id}:issue:{number}(immutable repo ID, survives renames) + content digest withsort_keys=Truefor deterministic ordering. - The prompt passes only the env-var name (
token_name), never the value, and scopes mutations to a single issue in a single repository. - Tests exercise the real
worker.pyentrypoint via thegithub_automation_helpersfixture, mocking only thesubmit_subject_turn/urlopenboundaries.
Non-blocking finding (unchanged)
SKILL.md's last paragraph (and the inlined skills/index.js content) still says "Each scheduled run triages at most one changed issue per repository," but the code uses continue (not break) and submits all changed eligible issues per run. The PR description already states the correct behavior. Documentation-only; does not block merge.
Verdict
No blocking findings. Explicitly approving.
Generated by OpenHands AI on behalf of the user.
all-hands-bot
left a comment
There was a problem hiding this comment.
Re-review of rebased head (4c0c313)
I re-reviewed the current rebased head (factory/triage-subject-turns @ 4c0c313) against main, re-ran the full suite, and re-checked catalog/bundle consistency.
Verification performed
- Full test suite: 905 passed, 24 skipped (includes the 3 triage delivery tests).
- Ruff: clean on
worker.pyandtest_github_triage_delivery.py. - Generated catalog:
npm run build:automationsandnpm run build:skillsproduce no diff —bundle-index.jsandskills/index.jsare in sync with source. - Bundle-index ↔ source:
worker.pyandgithub_client.pyinbundle-index.jsmatch the source files byte-for-byte.
Re-review observations
The rebased head is content-identical to the head I approved previously — the rebase replayed cleanly onto the latest main with no conflicts or changes. The architectural refactor (scanner delegates to Automation's subject-turn API; no SDK imports, no workspace/conversation lifecycle in the worker) remains sound:
submit_subject_turn()posts{source, subject_key, turn, idempotency_key}toAUTOMATION_SUBJECT_TURN_URLwith aBearer $AUTOMATION_RUN_TOKEN— no conversation/session/workspace machinery leaked into the scanner.- Idempotency keys are
{repository_id}:issue:{number}(immutable repo ID, survives renames) + content digest withsort_keys=Truefor deterministic ordering. - The prompt passes only the env-var name (
token_name), never the value, and scopes mutations to a single issue in a single repository. - Tests exercise the real
worker.pyentrypoint via thegithub_automation_helpersfixture, mocking only thesubmit_subject_turn/urlopenboundaries.
Non-blocking finding (unchanged)
SKILL.md's last paragraph (and the inlined skills/index.js content) still says "Each scheduled run triages at most one changed issue per repository," but the code uses continue (not break) and submits all changed eligible issues per run. The PR description already states the correct behavior. Documentation-only; does not block merge.
Verdict
No blocking findings. Explicitly approving.
Generated by OpenHands AI on behalf of the user.
|
@neubig I re-reviewed the current rebased head ( Verification performed:
The rebased head is content-identical to the head I approved previously — the rebase replayed cleanly onto the latest Non-blocking finding (unchanged): SKILL.md's last paragraph still says "Each scheduled run triages at most one changed issue per repository," but the code uses No blocking findings. Approved. Generated by OpenHands AI on behalf of the user. |
deec2ae to
05ad737
Compare
|
@all-hands-bot Please review the current head after the per-issue failure-isolation fix. If there are no material findings, please submit an approving review rather than only a comment. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Re-review of head 05ad737 — per-issue failure-isolation fix
I reviewed the current head (factory/triage-subject-turns @ 05ad737) after the per-issue failure-isolation commit, re-ran the full suite, and re-checked catalog/bundle consistency.
What changed since the last approval
The per-issue submission logic was extracted from run() into a new _submit(self, repository_id, issue, issues) method, and the run() loop now wraps each call in a try/except:
for issue in sorted(issues, key=lambda item: item["number"]):
try:
self._submit(repository_id, issue, issues)
except Exception as exc:
print(
f"Failed to submit {self.repository} issue "
f"#{issue.get('number', '?')}: {exc}",
flush=True,
)Previously a single submit_subject_turn failure (network error, 5xx from the Automation service, etc.) aborted the entire run, leaving all subsequent issues untriaged. Now each issue is isolated — a failure on one is logged and the remaining issues still get submitted. This mirrors the per-repository isolation already present in run_repositories (github_client.py).
The _submit method is a faithful extraction of the inline code: the early continue for already-triaged issues became an early return, which is equivalent. The idempotency keys, digest, marker, and prompt are unchanged.
Verification performed
- Full test suite: 906 passed, 24 skipped (includes the new
test_triage_continues_after_one_submission_failstest, which verifies that aRuntimeErroron issue #1 does not prevent issue #2 from being submitted). - Ruff: 1 finding on
worker.py(see non-blocking finding below).test_github_triage_delivery.pyis clean. - Generated catalog:
npm run build:automationsandnpm run build:skillsproduce no diff —bundle-index.jsandskills/index.jsare in sync with source. - Bundle-index ↔ source:
worker.pyandgithub_client.pyinbundle-index.jsmatch the source files byte-for-byte. - SKILL.md: The previously-noted stale throughput description ("at most one changed issue per repository") is now corrected — it reads "Each scheduled run submits every changed eligible issue. A failure on one issue is reported and does not prevent the remaining issues from being submitted."
Non-blocking finding
Ruff BLE001 regression on worker.py. The new except Exception as exc: at line 120 lacks the # noqa: BLE001 suppression that the codebase's established pattern uses (github_client.py line 196: except Exception as exc: # noqa: BLE001 - one repository must not block others). Consequently ruff check worker.py now reports one error. Ruff is not enforced in CI, so this does not break the build, but it is a lint regression from the previously-clean state. The fix is one line — add # noqa: BLE001 - one issue must not block others to match the convention.
Verdict
No blocking findings. The failure-isolation fix is correct, minimal, well-tested, and the generated assets are consistent. Approving.
Generated by OpenHands AI on behalf of the user.
|
@neubig I reviewed the current head ( Verification performed:
The fix: The per-issue submission logic was extracted into a Non-blocking finding: No blocking findings. Approved. Generated by OpenHands AI on behalf of the user. |
d3c3b1c to
ce3b6a6
Compare
9f485e7 to
dae808a
Compare
c96290d to
1e0a258
Compare
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
dae808a to
d3bb192
Compare
Co-authored-by: openhands <openhands@all-hands.dev>
d3bb192 to
b6cd5b7
Compare
Why
Issue polling and deduplication are deterministic scanner work. Only interpreting an issue, refining its acceptance criteria, and assigning priority require an agent. Keeping those boundaries separate lets one scan start several independent agents and lets Agent Server choose local or Docker execution.
Summary
Keep
github-issue-triageas a scheduled scanner. For each changed eligible issue it:ready-for-devdirectly on GitHub.The scanner contains no runtime provisioning, profile loading, or custom conversation API.
Issue Number
Closes #583.
How to Test
uv run --group test pytest -q tests/test_github_triage_delivery.py tests/test_automation_setup.pyResult: 126 passed, 18 skipped.
Dependencies
Review and merge #592 first. Running from Canvas with a selected profile additionally requires OpenHands/automation#479. Profile-selected saved secrets require OpenHands/software-agent-sdk#5017; Docker-backed conversations require OpenHands/software-agent-sdk#3403.
Live evidence
From a fresh UI-configured Canvas, the automation independently triaged Airbnb issues #81–#86. Issue #83's triage shows the readable rationale, explicit acceptance criteria, priority, and
ready-for-devresult produced by this head.